<?php

class WP_Version_Implementation extends WP_Version_Writer
{
	static public $handle = null;
	static private $typePrepare = null;
	static private $hookPrepare = null;
	static private $selectTypePrepare = null;
	static private $selectVersionPrepare = null;

	public function __destruct()
	{
		self::$handle = null;
		self::$typePrepare = null;
		self::$hookPrepare = null;
		self::$selectTypePrepare = null;
		self::$selectVersionPrepare = null;
	}

	public function setup()
	{
		self::$handle = new PDO('sqlite:'.SQLITE_PATH);
		self::$handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	}

	public function addFile($str)
	{
		$type = new WP_Version_Writer_Type();
		$type->version = $this->version;
		$type->definition = '';
		$type->name = $str;
		$type->type = WP_Version_Tokenizer::TYPE_FILE;

		$this->addType($type);
	}

	public function addConstant($str)
	{
		$type = new WP_Version_Writer_Type();
		$type->version = $this->version;
		$type->definition = '';
		$type->name = $str;
		$type->type = WP_Version_Tokenizer::TYPE_CONSTANT;

		$this->addType($type);
	}

	public function addGlobal($str)
	{
		$str = trim($str);
		$globals = explode(',', $str);

		$type = new WP_Version_Writer_Type();
		$type->version = $this->version;
		$type->type = WP_Version_Tokenizer::TYPE_GLOBAL;
		
		if( is_array($globals) )
		{
			foreach($globals as $def)
			{
				$global = rtrim(trim($def), '$');
				$type->definition = $global;
				$type->name = $global;
				$this->addType($type);
			}
		} else {
			$global = rtrim($str, '$');
			$type->definition = $global;
			$type->name = $global;
			$this->addType($type);
		}
	}

	public function addClassName($class)
	{
		$class = trim($class);
		$type = new WP_Version_Writer_Type();
		$type->version = $this->version;
		$type->type = WP_Version_Tokenizer::TYPE_CLASS;
		$type->definition = $class;
		$type->name = $class;
		$this->addType($type);
	}

	public function addFunction($str, $def)
	{
		$type = new WP_Version_Writer_Type();
		$type->version = $this->version;
		$type->definition = trim($def);
		$type->name = trim($str).'()';
		$type->type = WP_Version_Tokenizer::TYPE_FUNCTION;

		$this->addType($type);
	}

	public function addMethod($str, $classname)
	{
		$str = trim($str);
		preg_match("/^&?(.*?)\s*\(.*\)$/", $str, $match);
		$type = new WP_Version_Writer_Type();
		$type->version = $this->version;
		$type->definition = $match[0];
		$type->name = $classname.'::'.$match[1].'()';
		$type->type = WP_Version_Tokenizer::TYPE_METHOD;

		$this->addType($type);
	}

	public function addProperty($str, $classname)
	{
		$str = trim($str);
		if( strpos($str, ',') !== false )
		{
			$properties = explode(',', $str);
			foreach($properties as $property)
			{
				preg_match('/^$(.*?)(\s*=.*)?$/', $property, $match);
				$type = new WP_Version_Writer_Type();
				$type->version = $this->version;
				$type->definition = $match[0];
				$type->name = $classname.'::$'.$match[1];
				$type->type = WP_Version_Tokenizer::TYPE_PROPERTY;
		
				$this->addType($type);
			}
		}
		else
		{
			preg_match('/^\$(.*?)(\s*=.*)?$/', $str, $match);
			$type = new WP_Version_Writer_Type();
			$type->version = $this->version;
			$type->definition = $match[0];
			$type->name = $classname.'::$'.$match[1];
			$type->type = WP_Version_Tokenizer::TYPE_PROPERTY;
	
			$this->addType($type);
		}
	}

	public function addAction($hook, $def, $file)
	{
		$type = new WP_Version_Writer_Hook();
		$type->version = $this->version;
		$type->definition = trim($def);
		$type->name = trim($hook);
		$type->type = 'action';
		$type->file = $file;
		$type->line = 0;

		$this->addHook($type);
	}

	public function addFilter($hook, $def, $file)
	{
		$type = new WP_Version_Writer_Hook();
		$type->version = $this->version;
		$type->definition = trim($def);
		$type->name = trim($hook);
		$type->type = 'filter';
		$type->file = $file;
		$type->line = 0;

		$this->addHook($type);
	}

	public function addType(WP_Version_Writer_Type $type)
	{
		if( !is_object(self::$handle) )
		{
			trigger_error("Setup() has not be called, please call setup() method before beginning.", E_USER_ERROR);
		}

		if( !is_object(self::$typePrepare) )
		{
			self::$typePrepare = self::$handle->prepare("INSERT INTO wp_version_info (info_type, info_name, info_version, info_definition) VALUES (?,?,?,?);");
		}

		self::$typePrepare->execute(array($type->type, $type->name, $type->version, $type->definition));
	}

	public function addHook(WP_Version_Writer_Hook $hook)
	{
		if( !is_object(self::$hookPrepare) )
		{
			self::$hookPrepare = self::$handle->prepare("INSERT INTO wp_version_hook_info (hook_type, hook_name, hook_version, hook_definition, hook_file) VALUES (?,?,?,?,?);");
			self::$hookPrepare->bindParam(1, $hook->type, PDO::PARAM_STR, 20);
			self::$hookPrepare->bindParam(2, $hook->name, PDO::PARAM_STR, 255);
			self::$hookPrepare->bindParam(3, $hook->version, PDO::PARAM_STR, 20);
			self::$hookPrepare->bindParam(4, $hook->definition, PDO::PARAM_STR, 1000);
			self::$hookPrepare->bindParam(5, $hook->file, PDO::PARAM_STR, 512);
		}

		self::$hookPrepare->execute();
	}

	public function save()
	{
		unset(self::$handle);
	}

	public function dump()
	{
		var_dump(self::$handle->query("SELECT * FROM wp_version_info WHERE info_type = 2")->fetchAll(PDO::FETCH_ASSOC));
	}

	public function getClasses() { }

	public function getTypeNamesWithVersions($type)
	{
		if( !is_object(self::$selectTypePrepare) )
		{
			self::$selectTypePrepare = self::$handle->prepare("SELECT * FROM wp_types WHERE info_type = ? ORDER BY info_name ASC");
		}

		self::$selectTypePrepare->execute(array($type));

		return self::$selectTypePrepare->fetchAll(PDO::FETCH_ASSOC);
	}

	public function getTypes()
	{
		return array_keys( $this->info );
	}

	public function getNames($type)
	{
		return array_keys( $this->info[ $type ] );
	}

	public function getVersions($type, $name)
	{
		return $this->info[ $type ][ $name ];
	}
}

